Link to this headingDouble Ratchet
-
Uses Three Ratchets
- Root Ratchet: Ratchet happens when a user delivers a message with a new unknown DH key. This updates the keys for the Sending and Receiving Ratchet
- This provides Post-compromise security when a message is sent from the other user
- Sending Ratchet: Ratchets when need to encrypt a message
- This provides Perfect Forward Secrecy
- Receiving Ratchet: Ratchets when needs to decrypt a message
- This provides Perfect Forward Secrecy
- Root Ratchet: Ratchet happens when a user delivers a message with a new unknown DH key. This updates the keys for the Sending and Receiving Ratchet
-
Biased on Key Derivation Function Chains
- Generates new key each message for forward secrecy
- Also Generates a new key as input key for the next function
-
Has Forward Security
- Need both the previous Key and the new input to generate the new key
Example:
### x3DH Varables
=
=
=
=
= b
### Double Ratchet Variables
=
=
=
return
return None
return
return
return
#Return then remove key
return
=
=
=
return False
#print("[+] Signature Accepted")
=
return True
#Check from the correct User???
=
= 32
=
# Needs to be the same for each user
# This is the shared secret for the x3DH
=
=
=
=
#Setup KDF Chains
#DH shared key secrets are used for input to the root KDF Chain
=
#The root KDF Chain outputs are used as KDF keys for the sending and receiving chains
#Each incoming/outgoing message advances the chain. The outputs are used for the Symmetric Encryption/Decryption for each message
=
=
#Initialize the Root Chain
return
=
#Update RootKDF and return the rest of the output
, = ,
=
#Update SendingKDF and return the rest of the output
, = ,
=
#Update RecievingKDF and return the rest of the output
, = ,
return
return
#If inital_shared_secret is set then initialize the Chains as Symmetric Ratchet
#Use the x3DH shared secret from the username to generate the initial RootKDF
=
#Ratchet the Root KDF to initialize the Receive and Send Chains
=
=
#If sending then update the sending Keys first
, = ,
#print(f"Sending::initUserKDFs::SEM sending_keys[{username}]: {self.kdfchain_sending_keys[username].hex()}")
#print(f"Sending::initUserKDFs::SEM recieving_keys[{username}]: {self.kdfchain_recieving_keys[username].hex()}")
# Should only Trigger on an initialization sending
=
#print(f"Sending::initUserKDFs::DH initial dh_shared_secret[{username}]: {dh_shared_secret.hex()}")
#Update Root Ratchet with dh_shared_secret and update the receiving chain
=
#print(f"Sending::initUserKDFs::DH sending_keys[{username}]: {self.kdfchain_sending_keys[username].hex()}")
, = ,
#print(f"Receiving::initUserKDFs::SEM sending_keys[{username}]: {self.kdfchain_sending_keys[username].hex()}")
#print(f"Receiving::initUserKDFs::SEM recieving_keys[{username}]: {self.kdfchain_recieving_keys[username].hex()}")
#If the public key is also available do DH Ratchet
=
#Update Root Ratchet with dh_shared_secret and update the sending chain
=
#print(f"Receiving::initUserKDFs::DH recieving_keys[{username}]: {self.kdfchain_recieving_keys[username].hex()}")
#Update the Sending Ratchet
#Create and send keys to the server
=
#Get the dh_shared_secret for the sending
=
#print(f"Receiving::initUserKDFs::DH new dh_shared_secret[{username}]: {dh_shared_secret.hex()}")
#Update Root Ratchet with dh_shared_secret
#Set the sending_key for user
=
#print(f"Receiving::initUserKDFs::DH sending_keys[{username}]: {self.kdfchain_sending_keys[username].hex()}")
=
#Add the Signal Server to the user so You don't have to pass it through to all of the functions
=
### 3DH Specific Variables
=
#The Ed448 Private Key is 57 bits long while the x448 is 56 bits long
#https://crypto.stackexchange.com/questions/99974/curve448-can-ed448-key-material-be-reused-for-x448
# So we generate the x448 from the Ed448 key
=
=
=
=
=
#Lets Generate 5 Prekeys
### Double Ratchet Specific Variables
=
=
#Get Public Key
=
=
#Send to Server
=
#Lets get the required Data from the servers and check signatures
=
=
=
=
=
#Generate Ephemeral Key for the rest of the Key generation
=
=
#Check that the signature is correct for that key
return False
#Generate the 4 DH keys and generate secret
# DH1 = Alice Identity Key, Bob's Signed Pre_key
#Now that we have checked that the server did not give us the wrong user key Lets continue
=
#DH2 = Alice's Ephemeral Key, Bob's Identity Key
#Alice Generates a new Key for this exchange on the fly
=
#DH3 = Alice's Ephemeral Key, Bob's Signed Pre_key
=
#DH4 = Alice's Ephemeral Key, Bob's One Time Key
=
return
= 57*b
=
= 32*b
=
=
return
#Check if Signal Server has a Ratchet key for this User
=
#print(f"{self.username}::send_message: Get Ratchet Key From Server: {self.signal_server.getUsersDoubleRatchetKey(username).hex()}")
#for x in self.dh_ratchet_cache:
# print(f" {x}: {self.dh_ratchet_cache[x].public_bytes_raw().hex()}")
#Only add the x3DH information if needed
#Make sure to save the old dh key to add to the aad
=
#First time seeing this user do x3DH
#Check if already done x3dh. If not do it
#Initialize Ratchets knowing x3dh is done
=
#print(f"{self.username}::send_message: finish 3xDH dh_secret_key: {dh_secret_key.hex()}")
#Add x3DH to aad
=
#Init Ratchets
#Update DH Ratchet Cache
=
#Only update DH key when sending a message to another user
#print(f"{self.username}::send_message: send to server Ratchet Key: {self.users_ratchet.kdfchain_x448_key.public_key().public_bytes_raw().hex()}")
#Destiation's Ratchet DH key has been updated Update Ratchet
#Update DH Ratchet Cache
=
#Only update DH key when sending a message to another user
#print(f"{self.username}::send_message: send to server Ratchet Key: {self.users_ratchet.kdfchain_x448_key.public_key().public_bytes_raw().hex()}")
#Get message_sending Key from the ratchet
=
, = ,
#print(f"{self.username}::send_message: Encrypt with sending_key: {sending_key.hex()}, nonce: {nonce.hex()}")
#Encrypt and return all information
return
=
=
return
#Extract Information from message
, =
, , =
, , =
=
=
#Init Ratchets
#First time seeing this user do x3DH
### Start x3DH for the Recipient
=
#Generate DH1
# DH1 = Src Idenity Key, Dst Signed Pre_key
=
#Generate DH2
#DH2 = Src Ephemeral Key, Dst Identity Key
=
#Generate DH3
#DH3 = Src Ephemeral Key, Dst Signed Pre_key
=
#Generate DH4
#DH4 = Src Ephemeral Key, Dst One Time Key
=
=
#Generate Secret Key
=
#Init Ratchets
#Update DH Ratchet Cache
=
#Dont update signal server when receiving a message. Only when sending a message
#self.send_RatchetKeyToSignalServer()
#Destination's Ratchet DH key has been updated Update Ratchet
#Update DH Ratchet Cache
=
#Dont update signal server when receiving a message. Only when sending a message
#self.send_RatchetKeyToSignalServer()
#Get message_sending Key from the ratchet
=
, = ,
#Decrypt and Verify Cypher text
=
return
#Generate Server
=
#Generate Users
=
=
#Setup Users with the server
#x3DH Initialization
#DH Ratchet Key Initialization
#x3DH Initialization
#DH Ratchet Key Initialization
#Test 5 Messages from a single user
=
# Test 5 Ping Pong
=
=
#Test 5 Messages from a other user
=